package com.yimi.policyservice.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;

import com.yimi.policyservice.client.LoginClient;
import com.yimi.policyservice.client.UserClient;
import com.yimi.policyservice.common.constant.RedisConstant;
import com.yimi.policyservice.common.expetion.ApiException;

import com.yimi.policyservice.dao.system.SysUserMapperCustom;
import com.yimi.policyservice.dto.client.*;
import com.yimi.policyservice.dto.enums.ClientRusultEnum;
import com.yimi.policyservice.dto.enums.FunctionCodeEnum;
import com.yimi.policyservice.entity.base.system.*;
import com.yimi.policyservice.repository.*;
import com.yimi.policyservice.service.UserService;
import com.yimi.policyservice.utils.BeanHelper;
import com.yimi.policyservice.utils.SignUtil;
import com.yimi.policyservice.utils.TokenUtil;
import io.netty.util.internal.StringUtil;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.yimi.policyservice.dto.user.*;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository ;
    @Autowired
    private SysRoleRepository sysRoleRepository;

    @Autowired
    private SysPermissionRepository sysPermissionRepository ;

    @Autowired
    private StringRedisTemplate stringRedisTemplate ;

    @Autowired
    private SysUserRoleRepsitory sysUserRoleRepsitory ;

    @Autowired
    private SysUserMapperCustom sysUserMapperCustom ;

    @Autowired
    private OrganizationRepository organizationRepository ;

    @Autowired
    private SysMenuRepository sysMenuRepository ;

    @Autowired
    private LoginClient loginClient ;

    @Autowired
    private UserClient userClient ;

    private static final String MSG_LOGIN_USERNAMEPWD_ERROR = "用户名密码错误";

    private static final String MSG_LOGIN_USERSTATUS_ERROR = "用户已离职";
    private static final Integer isAdmin=1;

    @Value("${rootkey}")
    private String rootkey;
    @Value("${rsyLogin.enable}")
    private boolean enableRsyLogin;
    @Value("${rsyLogin.authCode}")
    private String authCode;
    @Value("${rsyLogin.appkey}")
    private String appkey;

    @Override
    public SysUser regist(User4Create bean) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(bean,sysUser);
        sysUser.setCreateDate(new Date());
        String encPwd = SecureUtil.md5(bean.getPassword());
        sysUser.setPassword(encPwd);
        userRepository.save(sysUser);
        addUserRole(bean.getRoles(),sysUser.getId());
        return sysUser;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserLogin4Get login(User4Login bean) {
        SysUser sysUser;
        boolean root =true;
        String jwtId ="";
        if(StringUtils.isBlank(bean.getPassword())){
            throw new ApiException(400, MSG_LOGIN_USERNAMEPWD_ERROR);
        }
        if(enableRsyLogin) {
            UserVO vo = rsyLogin(bean);
            sysUser =new SysUser();
            BeanUtils.copyProperties(vo,sysUser);
//            root=vo.getRoot();
            jwtId =vo.getToken();
        }else {
            jwtId =UUID.randomUUID().toString();
            sysUser = userRepository.findFirstByLoginNameAndPassword(bean.getLoginName(), SecureUtil.md5(bean.getPassword()));


            if (sysUser == null) {
                throw new ApiException(400, MSG_LOGIN_USERNAMEPWD_ERROR);
            }
            if (sysUser.getStatus() == 1) {
                throw new ApiException(400, MSG_LOGIN_USERSTATUS_ERROR);
            }

        }
        root = isRoot(sysUser);
        UserLogin4Get res = new UserLogin4Get();
        UserLoginInfo userLoginInfo = new UserLoginInfo();
        BeanUtils.copyProperties(sysUser,userLoginInfo);
        res.setUser(userLoginInfo);
        res.setRootKey(SecureUtil.md5(rootkey));
        List<SysPermission>permissions =new ArrayList<>();
        List<SysMenu> menus = new ArrayList<>();

        if(root){
            menus= sysMenuRepository.findAll();
            permissions=sysPermissionRepository.findAll();
        }else{
            menus= sysMenuRepository.findUserMenu(sysUser.getId());
            permissions = sysPermissionRepository.findUserPermisssions(sysUser.getId());
        }

        List<String> roles = sysUserRoleRepsitory.getUserRoleNames(sysUser.getId());
        res.setRoles(StringUtils.join(roles,","));
        res.setPermissionList(permissions);
        res.setToken(TokenUtil.createJWT(jwtId,sysUser.getId(),2*60*60*1000));
        res.setSysMenus(menus);
        saveUserCache(res.getToken(),userLoginInfo);
        return res;
    }

    //人是云登录平台登录
    private UserVO rsyLogin(User4Login bean) {
        SimpleDateFormat format=new SimpleDateFormat("yyyyMMddHHmmss");
        LoginPram param = new LoginPram();
        param.setUsername(bean.getLoginName());

        param.setSign_time(format.format(new Date()));
        param.setAuth_code(authCode);
        param.setAppkey(appkey);
        String[] signFields ={"username","password","auth_code","sign_time"};
        param.setPassword(bean.getPassword());
        try {
            String sign = SignUtil.generateSign(Arrays.asList(signFields),appkey, param);
            param.setSign(sign);

        } catch (Exception e) {
            e.printStackTrace();
        }

        String result = loginClient.login(param);
        LoginResult loginResult = JSONUtil.toBean(result, LoginResult.class);
        if(StringUtils.isBlank(loginResult.getStatus_code()) || !ClientRusultEnum.E00001.getCode().equals(loginResult.getStatus_code())){
            throw  new ApiException(400,loginResult.getStatus_message());
        }
        LoginUser result_data = loginResult.getResult_data();
        SysUser sysUser = userRepository.findFirstBySystemUserId(result_data.getUserid());
        if(sysUser==null){
            sysUser = new SysUser();
            sysUser.setLoginName(bean.getLoginName());
            sysUser.setId(result_data.getUserid());
            sysUser.setCreateDate(new Date());

        }
        sysUser.setSystemUserId(result_data.getUserid());
        if(StringUtils.isNotBlank(result_data.getEmail())) {
            sysUser.setEmail(result_data.getEmail());
        }
        if(StringUtils.isNotBlank(result_data.getRealname())) {
            sysUser.setName(result_data.getRealname());
        }
        if(StringUtils.isNotBlank(result_data.getMobile())) {
            sysUser.setTelephone(result_data.getMobile());
        }
        userRepository.save(sysUser);
        Boolean isRoot =true;
        if(isAdmin==result_data.getIs_administrator()) {
            String root = SecureUtil.md5(rootkey);
            String roleId = sysUserRoleRepsitory.getRootRole(sysUser.getId(), root);
            if(StringUtils.isBlank(roleId)){
                String rootId = sysRoleRepository.findIdByRoot(root);
                if(StringUtils.isNotBlank(rootId)){
                    isRoot =true;
                    SysUserRole userRole = new SysUserRole();
                    userRole.setRoleId(rootId);
                    userRole.setUserId(sysUser.getId());
                    userRole.setId(UUID.randomUUID().toString());
                    sysUserRoleRepsitory.save(userRole);
                }
            }
        }
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(sysUser,vo);
        vo.setRoot(isRoot);
        vo.setToken(result_data.getToken());
        return vo;
    }

    private boolean isRoot(SysUser sysUser) {
        String root =SecureUtil.md5(rootkey);
        String roleId = sysUserRoleRepsitory.getRootRole(sysUser.getId(), root);
        if(StringUtils.isNotBlank(roleId)){
            return true;
        }
        return false;
    }

    @Override
    public void checkLoginName(String loginName) {
        SysUser sysUser = userRepository.findFirstByLoginName(loginName);
        if(sysUser !=null ){
            throw  new ApiException(400,"用户已存在");
        }
    }

    @Override
    public void checkLogin(String token, FunctionCodeEnum functionCodeEnum) {
        //TODO 校验登录和权限
        if(StringUtils.isBlank(token)){
            throw  new ApiException(401,null);
        }
        String cache = stringRedisTemplate.opsForValue().get(token);
        if(StringUtils.isBlank(cache)){
            throw  new ApiException(401,null);
        }else{
            stringRedisTemplate.expire(token,TokenUtil.TOKEN_TOUT_MILLS,TimeUnit.MILLISECONDS);
        }
    }

    @Override
    public void updatePasswordBySmsCode(Password4Put bean) {
        String cacheKey = String.format(RedisConstant.SMS_TOKEN,bean.getToken());
        String cachePhone = stringRedisTemplate.opsForValue().get(cacheKey);
        if(StringUtils.isNotBlank(cachePhone)){
            SysUser sysUser = userRepository.findFirstByTelephone(cachePhone);
            if(sysUser != null){
                sysUser.setPassword(SecureUtil.md5(bean.getPassword()));
                userRepository.save(sysUser);
            }else{
                throw  new ApiException(500 ,"系统繁忙");
            }
        }else{
            throw  new ApiException(400 ,"短信验证码过期");
        }
    }

    @Override
    public void updatePasswordByOldPassword(String userId, Password4Put bean) {
        SysUser sysUser = userRepository.findById(userId).get();
        if(sysUser != null && StringUtils.equals(SecureUtil.md5(bean.getOldPassword()),sysUser.getPassword())){
            sysUser.setPassword(SecureUtil.md5(bean.getPassword()));
            userRepository.save(sysUser);
        }else{
            throw  new ApiException(400,"请输入正确的密码");
        }
    }


    @Override
    public void update(String userId, User4Put put) {
        SysUser sysUser = userRepository.findById(userId).get();
        BeanUtils.copyProperties(put,sysUser);
        userRepository.save(sysUser);

    }


    @Override
    public void loginOut(String token) {
        if(enableRsyLogin){
            String t = TokenUtil.JWTgetId(token);
            loginClient.logout(t);

        }
        stringRedisTemplate.delete(token);
    }


    @Override
    public Page<UserDto> search(List<String>roleIds, String deptId, String name) {
        return sysUserMapperCustom.search(roleIds,deptId,name);
    }


    @Override
    public void deleteUsers(List<String> ids) {
        if(ids.isEmpty()){
            return;
        }
        userRepository.deleteByIdIn(ids);
        sysUserRoleRepsitory.deleteByUserIdIn(ids);
    }


    @Override
    public List<SysOrganization> findAllDept() {
        return organizationRepository.findByStateOrderBySort(1);
    }

    @Override
    public UserDto getOne(String id) {
        UserDto user = sysUserMapperCustom.findOne(id);
        return user;
    }

    @Override
    public List<UserDto> findAllUser() {
        return sysUserMapperCustom.findAll();
    }

    @Override
    public List<String> findUserAllRoleId(String id) {
        return sysUserRoleRepsitory.findRoleIdByUserId(id);
    }

    @Override
    public void updateUser(String id, UserDto user) {
          SysUser sysUser = userRepository.findById(id).get();
          BeanHelper.copyProperties(user,sysUser);
          userRepository.save(sysUser);
          addUserRole(user.getRoleIds(),id);
    }


    private void addUserRole(List<String> roleIds,String userId){
         List<String> uids =  new ArrayList<>();
         uids.add(userId);
        sysUserRoleRepsitory.deleteByUserIdIn(uids);
        List<SysUserRole> roles = new ArrayList<>();
        for(String roleId: roleIds){
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRoleId(roleId);
            sysUserRole.setUserId(userId);
            roles.add(sysUserRole);
        }
        if(!roles.isEmpty()){
            sysUserRoleRepsitory.saveAll(roles);
        }
    }

    private void saveUserCache(String token, UserLoginInfo info){
        stringRedisTemplate.opsForValue().set(token, JSONUtil.toJsonStr(info),TokenUtil.TOKEN_TOUT_MILLS, TimeUnit.MILLISECONDS);
        stringRedisTemplate.opsForValue().set("userid:token:"+info.getId(),token,TokenUtil.TOKEN_TOUT_MILLS, TimeUnit.MILLISECONDS);
    }


    @Override
    public void updatePhone(String phone, String id) {
        userRepository.updatePhone(phone,id);
    }
    @Override
    @Async
    public void synUser(Integer page,Integer size,String token){
        if(enableRsyLogin){
            String t = TokenUtil.JWTgetId(token);
            String list = userClient.list(t, page, size);
            UserResult userResult = JSONUtil.toBean(list, UserResult.class);
            List<LoginUser> users = userResult.getResult_data();
            if(users==null||users.size()==0){

            }
            List<SysUser> sysUsers= new ArrayList<>();
            for(LoginUser user:users){
                SysUser sysUser = userRepository.findFirstBySystemUserId(user.getUserid());
                if(sysUser==null){
                    sysUser =new SysUser();
                    sysUser.setCreateDate(new Date());
                }
                sysUser.setLoginName(user.getUsername());
                if(StringUtils.isNotBlank(user.getRealname())) {
                    sysUser.setName(user.getRealname());
                }
                sysUser.setSystemUserId(user.getUserid());
                if(StringUtils.isNotBlank(user.getMobile())) {
                    sysUser.setTelephone(user.getMobile());
                }
                if(StringUtils.isNotBlank(user.getEmail())) {
                    sysUser.setEmail(user.getEmail());
                }
                sysUsers.add(sysUser);

            }

            userRepository.saveAll(sysUsers).size();

        }

    }
}
